package com.azt.provider.impl;

import com.azt.api.pojo.Category;
import com.azt.api.pojo.CategoryBrand;
import com.azt.api.pojo.Pcate;
import com.azt.api.service.ProCategoryBrandService;
import com.azt.api.service.ProCategoryService;
import com.azt.api.service.ProRepositoryService;
import com.azt.model.easy.EasyTree;
import com.azt.model.easy.EasyTreeModel;
import com.azt.model.page.Pagination;
import com.azt.provider.CategoryConstants;
import com.azt.provider.mapper.CategoryMapper;
import com.azt.provider.mapper.PcateMapper;
import com.azt.service.EasyService;
import com.azt.utils.MyCollectionUtils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xiaoleilu.hutool.util.CollectionUtil;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Service
@Transactional
public class ProCategoryServiceImpl implements ProCategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private PcateMapper pcateMapper;
    @Autowired
    private ProCategoryBrandService proCategoryBrandService;
    @Autowired
    private EasyService es;
    @Autowired
    private ProRepositoryService prs;


    @Override
    public Pagination getProCategoryPage(int pageno, int pagesize, Map<String, String> searchMap) {

        Page<Object> startPage = PageHelper.startPage(pageno, pagesize);
        List<Category> selectAll = categoryMapper.selectAll();
        Pagination pagination = new Pagination(startPage, selectAll);
        return pagination;
    }

    @Override
    public List<EasyTree> getProCategoryTree(Integer pid) {
        List<Category> listByParams = this.getAllCategoryByPid(pid);
        EasyTreeModel comboTreeModel = new EasyTreeModel("id", "name", "childenCategorys");
        comboTreeModel.setCodeField("code");
        Map<String, String> att = new HashMap<String, String>();
        att.put("cateType", "cateType");
        comboTreeModel.setAttributes(att);
        return es.easyTree(listByParams, comboTreeModel, null, false, false);
    }

    @Override
    public List<EasyTree> getCategorysTreeBack(Integer pid) {
        List<Category> listByParams = this.getCategorysByPidForTree(pid);
        EasyTreeModel comboTreeModel = new EasyTreeModel("id", "name", "childenCategorys");
        comboTreeModel.setCodeField("code");
        Map<String, String> att = new HashMap<String, String>();
        att.put("cateType", "cateType");
        comboTreeModel.setAttributes(att);
        return es.easyTree(listByParams, comboTreeModel, null, false, false);
    }


    @Override
    public List<Category> getAllCategoryByPid(Integer pid) {
        return categoryMapper.getCategorysByPid(pid);
    }

    @Override
    public List<Category> getCategorysByPidForTree(Integer pid) {
        return categoryMapper.getCategorysByPidForTree(pid);
    }

    @Override
    public List<Category> getCategorysByCateType(Integer catetype) {
        return categoryMapper.getCategorysByCateType(catetype);
    }

    @Override
    public void save(Category pro) {
        categoryMapper.insertSelective(pro);
    }

    @Override
    public Category getCategorysById(Integer proId) {
        if (proId == null) {
            return null;
        }
        Category category = new Category();
        category.setId(proId);
        return categoryMapper.selectOne(category);
    }

    @Override
    public Map<String, Category> getCategorysMap() {
        getAllCategories();//防止没有初始化
        return CategoryConstants.categoryByid;
    }


    @Override
    public Category getEntityById(Integer id) {
        Category category = new Category();
        category.setId(id);
        Category cate = categoryMapper.selectOne(category);
        return this.doSetAssociate(cate);
    }

    @Override
    public void saveOrUpdate(Category pc) {
        if (pc.getId() == null) {
            categoryMapper.insertSelective(pc);
        } else {
            categoryMapper.updateByPrimaryKeySelective(pc);
        }
    }


    @Override
    public void delete(Category pc) {
        if (pc != null) {
            categoryMapper.delete(pc);
        }
        if (pc.getCateType().compareTo(Category.CATE_TYPE_OF_PRODUCT) == 0) {
            prs.deleteByCategoryId(pc.getId());
        }
        if (CollectionUtil.isNotEmpty(pc.getChildenCategorys())) {
            deleteChildensPr(pc.getChildenCategorys());
        }
    }

    private void deleteChildensPr(List<Category> pcs) {
        for (Category pc : pcs) {
            if (pc.getCateType().compareTo(Category.CATE_TYPE_OF_PRODUCT) == 0) {
                prs.deleteByCategoryId(pc.getId());
            }
            if (CollectionUtil.isNotEmpty(pc.getChildenCategorys())) {
                deleteChildensPr(pc.getChildenCategorys());
            }
        }
    }

    @Override
    public List<Category> getCategoryByType(Integer type) {
        if (type != null) {
            Category category = new Category();
            category.setCateType(type);
            return categoryMapper.select(category);
        }
        return null;
    }

    @Override
    public String findCategoryNamesByIds(String ids) {
        String names = categoryMapper.getNamesByids(ids);
        return names == null ? "" : names;
    }

    @Override
    public String findCategoryNamesByCodes(String codes) {
        String names = categoryMapper.getNamesBycodes(codes);
        String sql = "select GROUP_CONCAT(name) from pro_category where FIND_IN_SET(code , ?)";
        return names == null ? "" : names;
    }

    @Override
    public List<Category> queryFathCategorys() {
        Category category = new Category();
        category.setPid(0);
        return categoryMapper.select(category);
    }

    @Override
    public List<Category> getChildenCategorys(Integer id) {
        Category ca = new Category();
        ca.setPid(id);
        return categoryMapper.select(ca);
    }

    @Override
    public Category getFatherCategorys(Integer pid) {
        Category ca = new Category();
        ca.setId(pid);
        return categoryMapper.selectOne(ca);
    }

    @Override
    public Category doSetAssociate(Category category) {
        if (category != null) {
            List<CategoryBrand> proCategoryBrands = proCategoryBrandService.ProCategoryBrandsByCategoryId(category.getId(), category.getCateType());
            List<Category> childenCategorys = this.getChildenCategorys(category.getId());
            Category fatherCategorys = this.getFatherCategorys(category.getPid());
            category.setChildenCategorys(childenCategorys);
            category.setProCategory(fatherCategorys);
            category.setProCategoryBrands(proCategoryBrands);
        }
        return category;
    }

    @Override
    public synchronized boolean proCategoryTempAuotCreate(int type) {
        //当pro_category表发生变化时,就返回true
        String timestr = categoryMapper.lastEditTime();
        Category c = new Category();
        c.setId(type);
        Category category = categoryMapper.selectByPrimaryKey(c);
        if (category == null) {
            category = new Category();
            category.setId(type);
            category.setRemoved(1);
            category.setPid(type);
            category.setCode("程序自动生成的" + type);
            category.setNickname(timestr);
            categoryMapper.insert(category);
            return true;
        } else {
            String code = category.getNickname();
            if (code == null || !code.equals(timestr)) {
                category.setId(type);
                category.setNickname(timestr);
                categoryMapper.updateByPrimaryKeySelective(category);
                return true;
            }
        }
        return false;
    }

    @Override
    public List<Category> findTopCategory() {
        Category category = new Category();
        category.setPid(0);
        category.setCateType(Category.CATE_TYPE_GEN);
        category.setRemoved(0);
        return categoryMapper.select(category);
    }

    @Override
    public void changeParent(Integer targetId, Integer id) {
        categoryMapper.changeParent(targetId, id);
    }

    @Override
    public Category getCategorysByCateCode(String code) {
        return categoryMapper.getCategorysByCateCode(code);
    }

    @Override
    public Pcate getPcateById(int pcateId) {
        return categoryMapper.getPcateById(pcateId);
    }

    @Override
    public void updatePcate(Pcate pcateById) {
        pcateMapper.updateByPrimaryKeySelective(pcateById);
    }

    @Override
    public List<Category> getAllCategory() {
        Category category = new Category();
        category.setRemoved(0);
        return categoryMapper.select(category);
    }

    @Override
    public List<Category> getCheckedCategoryByBrandId(Integer id) {
        return categoryMapper.getCheckedCategoryByBrandId(id);
    }

    @Override
    public Map<String, Integer> getParentCategorysIdBycategoryTId(Integer categoryTId) {
        if (categoryTId != null) {
            Map<String, Integer> CategorysMapId = categoryMapper.getParentCategorysIdBycategoryTId(categoryTId);
            if (CategorysMapId != null) {
                CategorysMapId.put("tid", categoryTId);
                return CategorysMapId;
            }
        }
        return null;
    }

    @Override
    public List<Category> findCategory(Integer id, Integer pid, Integer cateType) {
        Category category = new Category(id);
        category.setPid(pid);
        category.setCateType(cateType);
        category.setRemoved(0);
        return categoryMapper.select(category);
    }

    @Override
    public Map getParentCates(int cateId) {
        return categoryMapper.getParentCates(cateId);
    }


    ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    volatile boolean updating = false;//是否正在更新中

    @Override
    public List<Category> getAllCategories() {
        rwl.readLock().lock();
        //当pro_category表发生变化时,就返回true, 所有对象都带有关联,父子都有值
        try {
            String timestr = categoryMapper.lastEditTime();
            if (CategoryConstants.lastUpdateTime == null || (!CategoryConstants.lastUpdateTime.equals(timestr))) {
                updating = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (updating) {
            try {
                rwl.readLock().unlock();
                rwl.writeLock().lock();
                if (updating) {
                    List<Category> categories = categoryMapper.getAllCategory();
                    List<Category> pcates = new ArrayList<>();
                    Map<String, Category> mapCategory = new HashedMap();
                    Map<String, List<Category>> categoryByPid = new HashedMap();
                    //组织数据
                    for (Category category : categories) {
                        //key:id;value:category
                        mapCategory.put("" + category.getId(), category);

                        //key:pid;value:category
                        Integer pid = category.getPid();
                        List<Category> cc = categoryByPid.get(pid + "");
                        if (cc == null) {
                            cc = new ArrayList<Category>();
                            categoryByPid.put(pid + "", cc);
                        }
                        cc.add(category);


                        //给每个category加父子级
                        if (category.getPid() == 0) {
                            pcates.add(category);
                        } else {
                            Category c = mapCategory.get(pid + "");
                            category.setProCategory(c);
                            List<Category> childenCategorys = c.getChildenCategorys();
                            if (childenCategorys == null) {
                                List<Category> categoriess = new ArrayList<Category>();
                                categoriess.add(category);
                                c.setChildenCategorys(categoriess);
                            } else {
                                childenCategorys.add(category);
                                c.setChildenCategorys(childenCategorys);
                            }
                        }
                    }

                    CategoryConstants.categories = pcates;
                    CategoryConstants.categoryByid = mapCategory;
                    CategoryConstants.categroryByPid = categoryByPid;
                    CategoryConstants.lastUpdateTime = categoryMapper.lastEditTime();
                    updating = false;

                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                rwl.readLock().lock();
                rwl.writeLock().unlock();
            }
        }

        rwl.readLock().unlock();
        return CategoryConstants.categories;
    }


    @Override
    public Category getCacheCategoryById(Integer catid, boolean relationFather, boolean relationChild) {
        if (catid == null || catid==0) {
            return null;
        }
        getAllCategories();

        Category ccat = CategoryConstants.categoryByid.get(catid + "");

        if (relationFather && relationChild) {
            return ccat;
        }

        try {
            Category category = MyCollectionUtils.deepCopy(ccat);
            if (!relationFather) {
                category.setProCategory(null);
            }

            if (!relationChild) {
                //防止转json时,无限循环问题,不关联子节点时,将所有子节点设置为Null
                Category proCategory = category.getProCategory();
                if(proCategory!=null){
                    proCategory.setChildenCategorys(null);
                    Category pp = proCategory.getProCategory();
                    if(pp!=null){
                        pp.setChildenCategorys(null);
                    }
                }
                category.setChildenCategorys(null);
            }

            return category;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public List<Category> getCacheCategoryByPid(Integer pid, boolean relationFather, boolean relationChild) {
        if (pid == null) return null;
        getAllCategories();
        List<Category> categories = CategoryConstants.categroryByPid.get(pid + "");
        if (relationFather && relationChild) {
            return categories;
        } else {
            try {
                List<Category> newcategories = MyCollectionUtils.deepCopy(categories);
                for (Category newcategory : newcategories) {
                    if (!relationFather) {
                        newcategory.setProCategory(null);
                    }
                    if (!relationChild) {
                        newcategory.setChildenCategorys(null);
                    }
                }

                return newcategories;
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    @Override
    public List<Category> listAllCategoryBySize(int size) {
        return categoryMapper.selectCategoryBySize(size);
    }
}